/**
 * ProductTable.java 21 juil. 07
 * 
 * Copyright (c) 2007 windu.2b <jcaddie@windu2b.org>. All Rights Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.windu2b.jcaddie.swing;

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import java.util.*;
import java.util.List;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

import org.windu2b.jcaddie.model.*;
import org.windu2b.jcaddie.model.CaddiePieceOfProduct.*;
import org.windu2b.jcaddie.tools.*;
import org.windu2b.jcaddie.viewcontroller.*;

/**
 * @author windu.2b
 * 
 */
public class ProductTable extends JTable implements CoursesView,
        TableModelListener
{
	/**
	 * 
	 */
	private static final long	  serialVersionUID	= 6422874351373499303L;


	private ListSelectionListener	tableSelectionListener;


	private ProductTableModel	  ptm;




	/**
	 * @param caddie
	 * @param preferences
	 */
	public ProductTable( Caddie caddie, UserPreferences preferences )
	{
		this( caddie, preferences, null );
	}




	/**
	 * @param caddie
	 *            Le caddie auquel se rapporte la JTable
	 * @param preferences
	 *            Les préférences de l'utilisateur, nécessaires pour paramétrer
	 *            l'affichage
	 * @param controller
	 *            Le contrôleur des produits qu'il faut "écouter" pour se mettre
	 *            automatiquement à jour en cas de changement
	 */
	public ProductTable( Caddie caddie, UserPreferences preferences,
	        ProductController controller )
	{
		String[] columnNames = getColumnNames();
		ptm = new ProductTableModel( caddie, columnNames );
		setModel( ptm );
		setColumnIdentifiers();
		setColumnRenderers( preferences );
		setTableHeaderRenderer( caddie );
		updateTableSelectedProduct( caddie.getSelectedItems() );

		if ( controller != null )
		{
			addSelectionListeners( caddie, controller );
			// Enable sort in table with click in header
			addTableHeaderListener( controller );
			addMouseListener( controller );
		}
		addCaddieListener( caddie );
		addUserPreferencesListener( preferences );
		getModel().addTableModelListener( this );
	}




	/**
	 * @param caddie
	 * @param controller
	 */
	private void addSelectionListeners( final Caddie caddie,
	        final ProductController controller )
	{
		final SelectionListener coursesSelectionListener = new SelectionListener()
		{
			@SuppressWarnings( "unchecked" )
			public void selectionChanged( SelectionEvent ev )
			{
				updateTableSelectedProduct( ev.getSelectedItems() );
			}
		};

		tableSelectionListener = new ListSelectionListener()
		{
			public void valueChanged( ListSelectionEvent ev )
			{
				if ( !ev.getValueIsAdjusting() )
				{
					caddie.removeSelectionListener( coursesSelectionListener );
					int[] selectedRows = getSelectedRows();
					// Build the list of selected
					List<CaddiePieceOfProduct> selectedProduct = new ArrayList<CaddiePieceOfProduct>(
					        selectedRows.length );

					for ( int index : selectedRows )
					{
						// Add to selectedProduct table model first column
						// value that stores piece
						selectedProduct.add( caddie.getProduct( index ) );
					}
					// Set the new selection in caddie with controller
					controller.setSelectedProduct( selectedProduct );
					caddie.addSelectionListener( coursesSelectionListener );
				}
			}

		};
		getSelectionModel().addListSelectionListener( tableSelectionListener );
		caddie.addSelectionListener( coursesSelectionListener );
	}




	/**
	 * Ensures the rectangle which displays rows from <code>minIndex</code> to
	 * <code>maxIndex</code> is visible.
	 */
	private void makeRowsVisible( int minRow, int maxRow )
	{
		// Compute the rectangle that includes a row
		Rectangle includingRectangle = getCellRect( minRow, 0, true );
		if ( minRow != maxRow )
		{
			includingRectangle = includingRectangle.union( getCellRect( maxRow,
			        0, true ) );
		}
		if ( getAutoResizeMode() == AUTO_RESIZE_OFF )
		{
			int lastColumn = getColumnCount() - 1;
			includingRectangle = includingRectangle.union( getCellRect( minRow,
			        lastColumn, true ) );
			if ( minRow != maxRow )
			{
				includingRectangle = includingRectangle.union( getCellRect(
				        maxRow, lastColumn, true ) );
			}
		}
		scrollRectToVisible( includingRectangle );
	}




	private String[] getColumnNames()
	{
		ResourceBundle resource = ResourceBundle.getBundle( ProductTable.class
		        .getName() );
		String[] columnNames = { resource.getString( "checkedColumn" ),
		        resource.getString( "QuantiteColumn" ),
		        resource.getString( "nameColumn" ),
		        resource.getString( "priceColumn" ),
		        resource.getString( "priceTotalColumn" ) };

		return columnNames;
	}




	/**
	 * Sets column unique identifiers matching product sortable properties.
	 */
	private void setColumnIdentifiers()
	{
		CaddiePieceOfProduct.SortableProperty[] productProperties = {
		        SortableProperty.CHECKED, SortableProperty.QUANTITY,
		        SortableProperty.NAME, SortableProperty.UNIT_PRICE,
		        SortableProperty.TOTAL_PRICE };
		// Set identifiers of each column
		TableColumnModel columnModel = getColumnModel();
		for ( int i = 0, n = columnModel.getColumnCount(); i < n; i++ )
		{
			columnModel.getColumn( i ).setIdentifier( productProperties[i] );
		}
	}




	/**
	 * Sets column renderers.
	 */
	private void setColumnRenderers( UserPreferences preferences )
	{
		TableCellRenderer checkRenderer = getBooleanRenderer();
		TableCellRenderer quantiteRenderer = getQuantiteRenderer();
		TableCellRenderer nameRenderer = getProductNameRenderer();
		TableCellRenderer priceRenderer = getPriceRenderer( preferences );
		TableCellRenderer priceTotalRenderer = getPriceRenderer( preferences );

		TableCellRenderer[] columnRenderers = { checkRenderer,
		        quantiteRenderer, nameRenderer, priceRenderer,
		        priceTotalRenderer };

		TableColumnModel columnModel = getColumnModel();
		for ( int i = 0, n = getColumnCount(); i < n; i++ )
		{
			columnModel.getColumn( i ).setCellRenderer( columnRenderers[i] );
			/*
			 * getColumn( getColumnName( i ) ) .setCellRenderer(
			 * columnRenderers[i] );
			 */
		}
	}




	private TableCellRenderer getQuantiteRenderer()
	{
		return new SPinnerCellEditor();
	}




	private TableCellRenderer getProductNameRenderer()
	{
		return new DefaultTableCellRenderer()
		{
			/**
			 * 
			 */
			private static final long	serialVersionUID	= 2082226634566564026L;


			private static final int	COLUMN_ID			= 2;




			@Override
			public Component getTableCellRendererComponent( JTable table,
			        Object value, boolean isSelected, boolean hasFocus,
			        int row, int column )
			{
				Component result = super.getTableCellRendererComponent( table,
				        value, isSelected, hasFocus, row, column );
				if ( result instanceof JLabel )
				    ( ( JLabel ) result ).setToolTipText( ( String ) table
				            .getValueAt( row, COLUMN_ID ) );

				return result;
			}
		};
	}




	private TableCellRenderer getBooleanRenderer()
	{
		return new BooleanCellEditor();
	}




	/**
	 * @param preferences
	 * @return
	 */
	private TableCellRenderer getPriceRenderer(
	        final UserPreferences preferences )
	{
		final TableCellRenderer floatRenderer = getDefaultRenderer( Float.class );
		return new TableCellRenderer()
		{
			public Component getTableCellRendererComponent( JTable table,
			        Object value, boolean isSelected, boolean hasfocus,
			        int row, int column )
			{
				return floatRenderer.getTableCellRendererComponent( table,
				        value, isSelected, hasfocus, row, column );
			}
		};
	}




	/**
	 * Updates selected fiche in table from <code>selectedItems</code>.
	 */
	private void updateTableSelectedProduct( List<Object> selectedItems )
	{
		getSelectionModel()
		        .removeListSelectionListener( tableSelectionListener );
		clearSelection();
		ProductTableModel tableModel = ( ProductTableModel ) getModel();
		int minIndex = Integer.MAX_VALUE;
		int maxIndex = Integer.MIN_VALUE;
		for ( Object item : selectedItems )
		{
			if ( item instanceof CaddiePieceOfProduct )
			{
				// Search index of piece in sorted table model
				int index = tableModel
				        .getPieceOfProductIndex( ( CaddiePieceOfProduct ) item );
				addRowSelectionInterval( index, index );
				minIndex = Math.min( minIndex, index );
				maxIndex = Math.max( maxIndex, index );
			}
		}
		if ( minIndex != Integer.MIN_VALUE )
		{
			makeRowsVisible( minIndex, maxIndex );
		}
		getSelectionModel().addListSelectionListener( tableSelectionListener );
	}




	/**
	 * Adds a double click mouse listener to modify selected product.
	 */
	private void addMouseListener( final ProductController controller )
	{
		addMouseListener( new MouseAdapter()
		{
			@Override
			public void mouseClicked( MouseEvent ev )
			{
				if ( ev.getClickCount() == 1 )
				{
					int colIndex, rowIndex;
					Point p = ev.getPoint();
					colIndex = columnAtPoint( p );
					rowIndex = rowAtPoint( p );
					if ( colIndex == 0 )
					{
						if ( getValueAt( rowIndex, colIndex ) == Boolean.FALSE )
						{
							setValueAt( Boolean.TRUE, rowIndex, colIndex );
						}
						else setValueAt( Boolean.FALSE, rowIndex, colIndex );
					}
				}
				else if ( ev.getClickCount() == 2 )
				{
					// TODO gérer l'ajout via un double-clic
					System.out
					        .println( "Double-clic dans ProductTable.addMouseListener()" );
					controller.modifySelectedProduct();
				}
			}
		} );
	}




	private void addUserPreferencesListener( UserPreferences preferences )
	{
		preferences.addPropertyChangeListener( "unit",
		        new PropertyChangeListener()
		        {
			        public void propertyChange( PropertyChangeEvent arg0 )
			        {
				        repaint();
			        }
		        } );
	}




	/**
	 * Adds <code>PropertyChange</code> and
	 * {@link CoursesListener CoursesListener} listeners to caddie to update
	 * product sort in table when <code>productSortedProperty</code>,
	 * <code>productAscendingSorted</code> or product in <code>caddie</code>
	 * changes.
	 */
	private void addCaddieListener( final Caddie caddie )
	{
		PropertyChangeListener sortListener = new PropertyChangeListener()
		{
			public void propertyChange( PropertyChangeEvent ev )
			{
				( ( ProductTableModel ) getModel() ).sortProduct( caddie );
				// Update selected rows
				updateTableSelectedProduct( caddie.getSelectedItems() );
				getTableHeader().repaint();
			}
		};
		caddie.addPropertyChangeListener(
		        Caddie.Property.PRODUCT_SORTED_PROPERTY, sortListener );
		caddie.addPropertyChangeListener(
		        Caddie.Property.PRODUCT_DESCENDING_SORTED, sortListener );

		caddie.addCoursesListener( new CoursesListener()
		{
			public void pieceOfCoursesChanged( CoursesEvent ev )
			{
				if ( ev.getType() == CoursesEvent.Type.UPDATE )
				{
					// As product properties values change may alter sort
					// order, udpate sort and whole table
					( ( ProductTableModel ) getModel() ).sortProduct( caddie );
					// Update selected rows
					updateTableSelectedProduct( caddie.getSelectedItems() );
				}
				else if ( ev.getType() == CoursesEvent.Type.INCREMENT )
				{

				}
			}
		} );
	}




	/**
	 * Sets header renderer that displays an ascending or a descending icon when
	 * column is sorted.
	 */
	private void setTableHeaderRenderer( final Caddie caddie )
	{
		JTableHeader tableHeader = getTableHeader();
		final TableCellRenderer currentRenderer = tableHeader
		        .getDefaultRenderer();
		
		// Change table renderer to display the icon matching current sort
		tableHeader.setDefaultRenderer( new TableCellRenderer()
		{
			final ImageIcon	ascendingSortIcon	= new ImageIcon( ImageInJAR.getInstance().getImage( "ascending.png" ) );
			                                         /*  getClass()
			                                                   .getResource(
			                                                           "/org/windu2b/jcaddie/resources/ascending.png" ) );*/


			final ImageIcon	descendingSortIcon	= new ImageIcon( ImageInJAR.getInstance().getImage( "descending.png" ) );
													/*new ImageIcon(
			                                           getClass()
			                                                   .getResource(
			                                                           "/org/windu2b/jcaddie/resources/descending.png" ) );*/




			public Component getTableCellRendererComponent( JTable table,
			        Object value, boolean isSelected, boolean hasFocus,
			        int row, int column )
			{
				// Get default label
				JLabel label = ( JLabel ) currentRenderer
				        .getTableCellRendererComponent( table, value,
				                isSelected, hasFocus, row, column );
				// Add to column an icon matching sort
				TableColumnModel columnModel = getColumnModel();
				if ( columnModel.getColumn( column ).getIdentifier().equals(
				        caddie.getProductSortedProperty() ) )
				{
					label.setHorizontalTextPosition( JLabel.LEADING );
					if ( caddie.isProductDescendingSorted() )
					{
						label.setIcon( descendingSortIcon );
					}
					else
					{
						label.setIcon( ascendingSortIcon );
					}
				}
				else
				{
					label.setIcon( null );
				}
				return label;
			}
		} );
	}




	/**
	 * Adds a mouse listener on table header that will call
	 * <code>controller</code> sort method.
	 */
	private void addTableHeaderListener( final ProductController controller )
	{
		// Sort on click in column header
		getTableHeader().addMouseListener( new MouseAdapter()
		{
			@Override
			public void mouseClicked( MouseEvent ev )
			{
				int columnIndex = getTableHeader()
				        .columnAtPoint( ev.getPoint() );
				CaddiePieceOfProduct.SortableProperty property = ( CaddiePieceOfProduct.SortableProperty ) getColumnModel()
				        .getColumn( columnIndex ).getIdentifier();
				controller.sortProduct( property );
			}
		} );
	}



	/**
	 * Classe permettant de définir l'ordre et le type de champs à afficher
	 * 
	 * @author windu
	 * 
	 */
	private static class ProductTableModel extends AbstractTableModel
	{
		/**
		 * 
		 */
		private static final long		   serialVersionUID	= 4351219662523544273L;


		private Caddie		               caddie;


		private String[]		           columnNames;


		private List<CaddiePieceOfProduct>	sortedProduct;




		public ProductTableModel( Caddie caddie, String[] columnNames )
		{
			this.caddie = caddie;
			this.columnNames = columnNames;
			addCaddieListener( caddie );
			sortProduct( caddie );
		}




		/**
		 * @param caddie
		 */
		private void addCaddieListener( final Caddie caddie )
		{
			caddie.addCoursesListener( new CoursesListener()
			{
				public void pieceOfCoursesChanged( CoursesEvent ev )
				{
					int pieceIndex = ev.getIndex();
					CaddiePieceOfProduct piece = ( CaddiePieceOfProduct ) ev
					        .getPieceOfProduct();
					int sortedIndex = getPieceOfProductIndex( piece, caddie,
					        pieceIndex );
					switch ( ev.getType() )
					{
						// Ajout d'un nouveau produit dans la liste de courses
						case ADD :
						{
							sortedProduct.add( sortedIndex, piece );
							fireTableRowsInserted( pieceIndex, pieceIndex );
							break;
						}

							// Incrémentation d'un produit déjà présent dans la
							// liste de courses
						case INCREMENT :
						{
							fireTableRowsUpdated( pieceIndex, pieceIndex );
							break;
						}

							// Décrémentation d'un produit déjà présent dans la
							// liste de courses
						case DECREMENT :
						{
							fireTableRowsUpdated( pieceIndex, pieceIndex );
							break;
						}

							// Suppression d'un produit déjà présent dans la
							// liste de courses
						case DELETE :
						{
							sortedProduct.remove( sortedIndex );
							fireTableRowsDeleted( pieceIndex, pieceIndex );
							break;
						}
					}
				}




				/**
				 * Returns the index of <code>piece</code> in product table,
				 * with a default index of <code>caddiePieceIndex</code> if
				 * <code>caddie</code> product isn't sorted. If
				 * <code>piece</code> isn't added to product table, the
				 * returned value is equals to the insertion index where piece
				 * should be added.
				 */
				private int getPieceOfProductIndex( CaddiePieceOfProduct piece,
				        Caddie caddie, int caddiePieceIndex )
				{
					if ( caddie.getProductSortedProperty() == null )
					{
						return caddiePieceIndex;
					}
					else
					{
						int sortedIndex = Collections.binarySearch(
						        sortedProduct, piece,
						        getProductComparator( caddie ) );
						if ( sortedIndex >= 0 )
						{
							return sortedIndex;
						}
						else
						{
							return -( sortedIndex + 1 );
						}
					}
				}
			} );
		}




		@Override
		public String getColumnName( int columnIndex )
		{
			return columnNames[columnIndex];
		}




		/**
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		public int getColumnCount()
		{
			return columnNames.length;
		}




		/**
		 * @see javax.swing.table.TableModel#getRowCount()
		 */
		public int getRowCount()
		{
			return caddie.getProduct().size();
		}




		/**
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		public Object getValueAt( int rowIndex, int columnIndex )
		{
			CaddiePieceOfProduct piece = caddie.getProduct().get( rowIndex );

			switch ( columnIndex )
			{
				case 0 :
					return piece.isChecked();
				case 1 :
					return piece.getQuantite();
				case 2 :
					return piece.getName();
				case 3 :
					return piece.getPrice();
				case 4 :
					return piece.getTotalPrice();
				default :
					throw new IllegalArgumentException( "Unknown column"
					        + columnIndex );
			}
		}




		@Override
		public void setValueAt( Object value, int rowIndex, int colIndex )
		{
			CaddiePieceOfProduct piece = caddie.getProduct( rowIndex );

			if ( colIndex == 0 )
			{
				/**
				 * Si la valeur est <code>false</code>,on décoche le
				 * JCheckbox, On rend le JSpinner éditable et on déraye le
				 * JLabel contenant le nom du produit
				 */
				if ( value == Boolean.FALSE )
				{
					piece.setChecked( Boolean.FALSE );
					piece.setEditable( Boolean.FALSE );
					piece.setState( State.TYPE.UNSTRIKE );
				}
				/**
				 * Si la valeur est <code>true</code>,on coche le JCheckbox,
				 * On rend le JSpinner non-éditable et on raye le JLabel
				 * contenant le nom du produit pour indiquer que le produit a
				 * été correctement récupéré
				 */
				else
				{
					piece.setChecked( Boolean.TRUE );
					piece.setEditable( Boolean.TRUE );
					piece.setState( State.TYPE.STRIKE );
				}
			}

			// Avertissement des listeners
			fireTableRowsUpdated( rowIndex, rowIndex );/*
														 * Changed( new
														 * TableModelEvent(
														 * this, rowIndex,
														 * rowIndex, colIndex ) );
														 * fireTableChanged( new
														 * TableModelEvent(
														 * this, rowIndex,
														 * rowIndex, colIndex +
														 * 1 ) );
														 * fireTableChanged( new
														 * TableModelEvent(
														 * this, rowIndex,
														 * rowIndex, colIndex +
														 * 2 ) );
														 */
		}




		/**
		 * Returns the index of <code>piece</code> in product table.
		 */
		public int getPieceOfProductIndex( CaddiePieceOfProduct piece )
		{
			return sortedProduct.indexOf( piece );
		}




		/**
		 * Sorts <code>caddie</code> product.
		 */
		public void sortProduct( Caddie caddie )
		{
			this.sortedProduct = new ArrayList<CaddiePieceOfProduct>( caddie
			        .getProduct() );
			if ( caddie.getProductSortedProperty() != null )
			{
				Comparator<CaddiePieceOfProduct> productComparator = getProductComparator( caddie );
				Collections.sort( this.sortedProduct, productComparator );
			}

			fireTableRowsUpdated( 0, getRowCount() - 1 );
		}




		private Comparator<CaddiePieceOfProduct> getProductComparator(
		        Caddie caddie )
		{
			Comparator<CaddiePieceOfProduct> productComparator = CaddiePieceOfProduct
			        .getProductComparator( caddie.getProductSortedProperty() );
			if ( caddie.isProductDescendingSorted() )
			{
				productComparator = Collections
				        .reverseOrder( productComparator );
			}
			return productComparator;
		}




		@Override
		public boolean isCellEditable( int rowIndex, int columnIndex )
		{
			/*
			 * if ( columnIndex == 0 || columnIndex == 1 ) return true; else
			 * return false;
			 */
			return true;
		}
	}

	private class BooleanCellEditor extends AbstractCellEditor implements
	        TableCellEditor, TableCellRenderer, ItemListener
	{
		/**
		 * 
		 */
		private static final long	serialVersionUID	= 8806122021095950985L;


		JCheckBox		          jCheckBox		     = new JCheckBox();




		public Component getTableCellEditorComponent( JTable jTable,
		        Object value, boolean isSelected, int rowIndex, int vColIndex )
		{
			jCheckBox.setHorizontalAlignment( SwingConstants.CENTER );
			boolean bValue = ( ( Boolean ) value ).booleanValue();
			if ( bValue == false )
			{
				return null;
			}
			else
			{
				// Fixer l'état de départ
				jCheckBox.setSelected( bValue );
				jCheckBox.addItemListener( this );
				return jCheckBox;
			}
		}




		public Object getCellEditorValue()
		{
			return Boolean.valueOf( jCheckBox.isSelected() );
		}




		@Override
		public boolean isCellEditable( EventObject evt )
		{
			if ( evt instanceof MouseEvent )
			{
				// For single-click activation
				int clickCount = 1;
				return ( ( MouseEvent ) evt ).getClickCount() >= clickCount;
			}
			return true;
		}




		public Component getTableCellRendererComponent( JTable table,
		        Object value, boolean isSelected, boolean hasFocus, int row,
		        int column )
		{
			// Create a panel and add the check box to it.
			JCheckBox checkBox = new JCheckBox();
			checkBox.setHorizontalAlignment( JLabel.CENTER );
			checkBox.setSelected( ( ( Boolean ) value ).booleanValue() );

			return checkBox;
		}




		public void itemStateChanged( ItemEvent ev )
		{
			if ( ev.getSource() instanceof JCheckBox )
			{
				// TODO je sais pas encore quoi y mettre
			}
		}
	}

	private class SPinnerCellEditor extends AbstractCellEditor implements
	        TableCellEditor, TableCellRenderer, ChangeListener
	{
		/**
		 * 
		 */
		private static final long	serialVersionUID	= 2082226634566564026L;


		private JSpinner		  jSpinner;


		private static final int	MIN_VALUE		 = Integer.MIN_VALUE;


		private static final int	MAX_VALUE		 = Integer.MAX_VALUE;


		private static final int	STEP_VALUE		 = 1;




		/**
		 * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable,
		 *      java.lang.Object, boolean, int, int)
		 */
		public Component getTableCellEditorComponent( JTable jTable,
		        Object value, boolean isSelected, int rowIndex, int vColIndex )
		{
			boolean bValue = ( ( Boolean ) value ).booleanValue();
			if ( bValue == false )
			{
				return null;
			}
			else
			{
				jSpinner.addChangeListener( this );

				return jSpinner;
			}
		}




		public Object getCellEditorValue()
		{
			return Boolean.valueOf( jSpinner.isEnabled() );
		}




		public Component getTableCellRendererComponent( JTable table,
		        Object value, boolean isSelected, boolean hasFocus, int row,
		        int column )
		{
			JSpinner spinner = new JSpinner( new SpinnerNumberModel( Integer
			        .parseInt( value.toString() ), MIN_VALUE, MAX_VALUE,
			        STEP_VALUE ) );
			spinner.setEnabled( true );
			JFormattedTextField tf = ( ( JSpinner.DefaultEditor ) spinner
			        .getEditor() ).getTextField();
			tf.setEnabled( true );
			tf.setEditable( true );
			// tf.setBackground( Color.GREEN );

			return spinner;
		}




		/**
		 * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
		 */
		public void stateChanged( ChangeEvent ev )
		{
			if ( ev.getSource() instanceof JSpinner )
			{
				// TODO je sais pas encore quoi y mettre
			}
		}

	}
}